// -*- c-basic-offset: 2 default-tab-width: 2 indent-tabs-mode: t -*-
// vim: autoindent tabstop=2 noexpandtab shiftwidth=2 softtabstop=2
//===------------ VirtualTables.cpp
//
//             This file is part of the reactor project
//                Author: R-Core Team
//
//===---------------------------------------------------------------------===//

#include "Stack.h"
#include "Reactor.h"
#include "RModule.h"

#include "Any.h"
#include "Environment.h"
#include "Array.h"
#include "Closure.h"
#include "Promise.h"
#include "Evaluator.h"
#include "Bindings.h"

using namespace R;


/******************************************************************************
 *                              Virtual Tables Init                           *
 *****************************************************************************/

// sets correctly virtual vt members of given Class
//
#define init_virtualVT(NAME, hasDestructor)															\
	RVirtualTable* NAME::virtualVT =																			\
    new RVirtualTable(NAME::ID, Any::getOrigVT<NAME>(), hasDestructor)

#define init_pseudoVT(NAME, hasDestructor)															\
	RVirtualTable* NAME::virtualVT =																			\
    Any::getOrigVT<NAME>();

init_virtualVT(Symbol, 0);
init_virtualVT(Closure, 0);
init_virtualVT(Promise, 0);
init_virtualVT(Int, 0);
init_virtualVT(Double, 0);
init_virtualVT(Logical, 0);
init_virtualVT(String, 0);
init_virtualVT(Vector, 0);

init_pseudoVT(CollectableEnvironment, 0);
init_pseudoVT(Bindings, 0);

#undef init_virtualVT
#undef init_pseudoVT


/******************************************************************************
 *                              Any tracers                               *
 *****************************************************************************/

void Reactor::tracer(word_t closure) {
  //fprintf(stderr, "[tracer]: Reactor\t@%p\n", this);
  // Tracing global roots

	/* must be here because we are sure that this tracer is only called once */
	Any::markAndTraceRoot(&ConstPool::True, closure);
	Any::markAndTraceRoot(&ConstPool::False, closure);
	Any::markAndTraceRoot(&ConstPool::Null, closure);

	for(int i=0; i<modules.size(); i++)
		modules.get(i)->tracer(closure);
}

void Evaluator::tracer(word_t closure) {
  //fprintf(stderr, "[tracer]: Evaluator\t@%p\n", this);
	stack->tracer(closure);
}

void AnyStack::tracer(word_t closure) {
	for(int i=0; i<size(); i++)
		Any::markAndTraceRoot(stackAny + i, closure);
}

void EnvStack::tracer(word_t closure) {
	for (int i = 0; i < size(); i++) {
		if (stack[i].isGc) {
			Any::markAndTraceRoot(&(stack[i].env_gc), closure);
		}
	}
}

void Stack::tracer(word_t closure) {
	anyStack.tracer(closure);
	envStack.tracer(closure);
}

void RModule::tracer(word_t closure) {
  //fprintf(stderr, "[tracer]: RModule\t@%p\n", this);

  cpool.tracer(closure);
	for (int i = 0; i < nbFuns; i++)
		funInfos[i].tracer(closure);
	if(environment)
		environment->tracer(closure);
}

void FunInfo::tracer(word_t closure) {
	if(bindings)
		Any::markAndTraceRoot(&bindings, closure);
}

void ConstPool::tracer(word_t closure) {
  for (int i = 0; i < size; i++)
    if ((data[i])) Any::markAndTraceRoot((data + i), closure);
}

void Any::tracer(word_t closure) {
  //fprintf(stderr, "[tracer]: Any\t@%p\n", this);
  if (attributes) {
    markAndTrace(this, &attributes, closure);
  }
}

void Symbol::tracer(word_t closure) {
	if(value)
		markAndTrace(this, this->value, closure);
	Any::tracer(closure);
}

void CollectableEnvironment::tracer(word_t closure) {
  //fprintf(stderr, "[tracer]: CollectableEnvironment\t@%p\n", this);
  if(enclosing)	markAndTrace(this, &enclosing, closure);
	if(bindings)	markAndTrace(this, &bindings, closure);
	for (int i = 0; i < this->length() ; i++)
		markAndTrace(this, this->content + i, closure);
	Any::tracer(closure);
}

void Closure::tracer(word_t closure) {
	if(env) markAndTrace(this, &env, closure);
	Lambda::tracer(closure);
}

void Promise::tracer(word_t closure) {
  //fprintf(stderr, "[tracer]: Promise\t@%p\n", this);
//	envInfo->tracer(closure);
  if (value) markAndTrace(this, &value, closure);
  Lambda::tracer(closure);
}

void Lambda::tracer(word_t closure) {
  Atom::tracer(closure);
}

void Bindings::tracer(word_t closure) {
	//printf("Trace bindings %p: %d %p\n", this, size, &size);
	for(int i=0; i<size; i++) {
		if(content[i].key)
			markAndTrace(this, &content[i].key, closure);
		if(content[i].value)
			markAndTrace(this, &content[i].value, closure);
	}
	Any::tracer(closure);
}


void Vector::tracer(word_t closure) {
	asSelf(Vector);
	for (int i = 0; i < self->length; i++)
		markAndTrace(self, self->content + i, closure);
	Array::tracer(closure);
}
